#ifndef MIPSPROCESSORSTATE_H
#define MIPSPROCESSORSTATE_H


#include <iostream>
#include "crossbit/ProcessorState.h"
#include "string.h"

namespace crossbit {

				class MIPSProcessorState : public ProcessorState
				{
								public:
												/* total 35 internal registers numbered 0, 1, ..., 33 */
												enum PISA {
																$zero = 0,				// $0, zero-valued souce
																$at,					// $1, reserved by assembler
																$v0, $v1,				// $2-$3, fn return result regs
																$a0, $a1, $a2, $a3,			// $4-$7, fn argument value regs
																$t0, $t1, $t2, $t3, $t4, $t5, $t6, $t7, // $8-$15, temp regs, caller saved, general-purpose
																$s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7, // $16-$23, saved regs, callee saved, general-purpose
																$t8, $t9,				// $24-$25, temp regs, caller saved, general-purpose
																$k0, $k1,				// $26-$27, reserved by OS
																$gp,					// $28, global pointer
																$sp,					// $29, stack pointer
																$s8,					// $30, saved reg, callee saved
																$ra,					// $31, return address reg
																$hi,					// high result register
																$lo,					// low result register
																EOR					//end of register
												};

												enum FP {					//Float point register
																$f0 = 0,
																$f1,
																$f2,
																$f3,
																$f4,
																$f5,
																$f6,
																$f7,
																$f8,
																$f9,
																$f10,
																$f11,
																$f12,
																$f13,
																$f14,
																$f15,
																$f16,
																$f17,
																$f18,
																$f19,
																$f20,
																$f21,
																$f22,
																$f23,
																$f24,
																$f25,
																$f26,
																$f27,
																$f28,
																$f29,
																$f30,
																$f31,
																$fcc,					//Float point condition code register
																$fcw,EOFR
												};


												MIPSProcessorState() 
												{
																// initialize registers to zero
																memset((void *)&regs, 0, sizeof(regs));
																memset((void *)&fp_regs, 0, sizeof(fp_regs));
												}


												MIPSProcessorState *getProcessorState()
												{
																return this;
												}
												// Get the memory address of the simulated register
												XTMemAddr get(XTRegNum reg) const
												{
																return (XTMemAddr) (regs + reg);
												}

												// Get the value of the simulated register
												XTInt32 reg(XTRegNum reg) const
												{
																//return static_cast<Word>( 0xffffffff & regs[reg]);
																return regs[reg];
												}

												// Set the value of simulated register
												void put(XTRegNum reg, XTInt32 value)
												{
																//		regs[reg] = static_cast<DWord>(~0) & value;
																regs[reg] = value;
												}

												// Get the number of *general-purpose* register
												int size() const
												{
																// $0-32, $hi, $lo
																return EOR;
												}

												XTMemAddr fpGet(XTRegNum reg) const
												{
																return (XTMemAddr) (fp_regs + reg);
												}

												// Get the value of the simulated register
												XTInt32 fpReg(XTRegNum reg) const
												{
																return fp_regs[reg];
												}

												// Set the value of simulated register
												void fpPut(XTRegNum reg, XTInt32 value)
												{
																fp_regs[reg] = value;
												}

												// Get the number of float-point register
												int fpSize() const
												{
																// $0-31, $fcc
																return EOFR;
												}

												MIPSProcessorState( const MIPSProcessorState& state )
												{
																int i;

																for( i = 0; i < size(); i ++ )
																{
																				regs[i] = state.regs[i];
																}

																for( i = 0; i < fpSize(); i ++ )
																{
																				fp_regs[i] = state.fp_regs[i];
																}
												}

												const MIPSProcessorState& operator= ( const MIPSProcessorState& state )
												{
																int i;

																for( i = 0; i < size(); i ++ )
																{
																				regs[i] = state.regs[i];
																}

																for( i = 0; i < fpSize(); i ++ )
																{
																				fp_regs[i] = state.fp_regs[i];
																}
																return *this;
												}

												// Dump the register file
												void dump()
												{
																std::cout << "MIPS Register File Dump: " << std::endl
																				<< "\t$zero 0x"<< std::hex << *(XTUint32*)&regs[$zero]<<std::endl
																				<< "\t$at: 0x" << std::hex << *(XTUint32*)&regs[$at] << std::endl
																				<< "\t$v0: 0x" << std::hex <<  *(XTUint32 *)&regs[$v0] << std::endl
																				<< "\t$v1: 0x" << std::hex << *(XTUint32 *)&regs[$v1] <<  std::endl
																				<< "\t$a0: 0x" << std::hex << *(XTUint32 *)&regs[$a0] <<  std::endl
																				<< "\t$a1: 0x" << std::hex << *(XTUint32 *)&regs[$a1] <<  std::endl 
																				<< "\t$a2: 0x" << std::hex << *(XTUint32 *)&regs[$a2] <<  std::endl
																				<< "\t$a3: 0x" << std::hex << *(XTUint32 *)&regs[$a3] <<  std::endl
																				<< "\t$t0: 0x" << std::hex << *(XTUint32 *)&regs[$t0] <<  std::endl
																				<< "\t$t1: 0x" << std::hex << *(XTUint32 *)&regs[$t1] <<  std::endl
																				<< "\t$t2: 0x" << std::hex << *(XTUint32 *)&regs[$t2] <<  std::endl
																				<< "\t$t3: 0x" << std::hex << *(XTUint32 *)&regs[$t3] <<  std::endl
																				<< "\t$t4: 0x" << std::hex << *(XTUint32 *)&regs[$t4] <<  std::endl
																				<< "\t$t5: 0x" << std::hex << *(XTUint32 *)&regs[$t5] <<  std::endl
																				<< "\t$t6: 0x" << std::hex << *(XTUint32 *)&regs[$t6] <<  std::endl
																				<< "\t$t7: 0x" << std::hex << *(XTUint32 *)&regs[$t7] <<  std::endl
																				<< "\t$s0: 0x" << std::hex << *(XTUint32 *)&regs[$s0] <<  std::endl
																				<< "\t$s1: 0x" << std::hex << *(XTUint32 *)&regs[$s1] <<  std::endl
																				<< "\t$s2: 0x" << std::hex << *(XTUint32 *)&regs[$s2] <<  std::endl
																				<< "\t$s3: 0x" << std::hex << *(XTUint32 *)&regs[$s3] <<  std::endl
																				<< "\t$s4: 0x" << std::hex << *(XTUint32 *)&regs[$s4] <<  std::endl
																				<< "\t$s5: 0x" << std::hex << *(XTUint32 *)&regs[$s5] <<  std::endl
																				<< "\t$s6: 0x" << std::hex << *(XTUint32 *)&regs[$s6] <<  std::endl
																				<< "\t$s7: 0x" << std::hex << *(XTUint32 *)&regs[$s7] <<  std::endl
																				<< "\t$t8: 0x" << std::hex << *(XTUint32 *)&regs[$t8] <<  std::endl
																				<< "\t$t9: 0x" << std::hex << *(XTUint32 *)&regs[$t9] <<  std::endl
																				<< "\t$k0: 0x" << std::hex << *(XTUint32 *)&regs[$k0] <<  std::endl
																				<< "\t$k1: 0x" << std::hex << *(XTUint32 *)&regs[$k1] <<  std::endl
																				<< "\t$gp: 0x" << std::hex << *(XTUint32 *)&regs[$gp] <<  std::endl
																				<< "\t$sp: 0x" << std::hex << *(XTUint32 *)&regs[$sp] <<  std::endl
																				<< "\t$s8: 0x" << std::hex << *(XTUint32 *)&regs[$s8] <<  std::endl
																				<< "\t$ra: 0x" << std::hex << *(XTUint32 *)&regs[$ra] <<  std::endl
																				<< "\t$hi: 0x" << std::hex << *(XTUint32 *)&regs[$hi] <<  std::endl
																				<< "\t$lo: 0x" << std::hex << *(XTUint32 *)&regs[$lo] <<  std::endl
																				<< "PISA Float Point Register Dump:" << std::endl;
																int i;
																for ( i = 0; i < 34; i++)
																				std::cout << "\t$f" <<(XTInt32)i<< ": 0x"
																								<< std::hex << fp_regs[i] 
																								<< std::endl;
												}

								private:
												volatile XTInt32 regs[EOR];
												volatile XTInt32 fp_regs[EOFR];
				};

}

#endif
